package com.bjw.ComAssistant;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

import com.bjw.bean.AssistBean;
import com.bjw.bean.ComBean;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.os.Bundle;
import android.text.InputType;
import android.text.method.KeyListener;
import android.text.method.NumberKeyListener;
import android.text.method.TextKeyListener;
import android.text.method.TextKeyListener.Capitalize;
import android.util.Base64;
import android.view.KeyEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;

import android_serialport_api.SerialPortFinder;

/**
 *
 */
public class ComAssistantActivity extends Activity {
    EditText editTextRecDisp, editTextLines, editTextCOMA, editTextCOMB, editTextCOMC, editTextCOMD;
    EditText editTextTimeCOMA, editTextTimeCOMB, editTextTimeCOMC, editTextTimeCOMD;
    CheckBox checkBoxAutoClear, checkBoxAutoCOMA, checkBoxAutoCOMB, checkBoxAutoCOMC, checkBoxAutoCOMD;
    Button ButtonClear, ButtonSendCOMA, ButtonSendCOMB, ButtonSendCOMC, ButtonSendCOMD;
    ToggleButton toggleButtonCOMA, toggleButtonCOMB, toggleButtonCOMC, toggleButtonCOMD;
    Spinner SpinnerCOMA, SpinnerCOMB, SpinnerCOMC, SpinnerCOMD;
    Spinner SpinnerBaudRateCOMA, SpinnerBaudRateCOMB, SpinnerBaudRateCOMC, SpinnerBaudRateCOMD;
    RadioButton radioButtonTxt, radioButtonHex;
    SerialControl ComA, ComB, ComC, ComD;//4������
    DispQueueThread DispQueue;//ˢ����ʾ�߳�
    SerialPortFinder mSerialPortFinder;//�����豸����
    AssistBean AssistData; // 输出文本默认值
    int iRecLines = 0;//����������

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ComA = new SerialControl();
        ComB = new SerialControl();
        ComC = new SerialControl();
        ComD = new SerialControl();
        DispQueue = new DispQueueThread();
        DispQueue.start();
        AssistData = getAssistData();
        setControls();
    }

    @Override
    public void onDestroy() {
        // 保存默认数据
        saveAssistData(AssistData);
        // 关闭串口
        CloseComPort(ComA);
        CloseComPort(ComB);
        CloseComPort(ComC);
        CloseComPort(ComD);
        super.onDestroy();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        CloseComPort(ComA);
        CloseComPort(ComB);
        CloseComPort(ComC);
        CloseComPort(ComD);
        setContentView(R.layout.main);
        setControls();
    }

    /**
     * 初始化页面控件方法
     */
    private void setControls() {
        // 设置主界面标题为软件名+版本号
        String appName = getString(R.string.app_name);
        try {
            // 读取build.gradle的版本号
            PackageInfo pinfo = getPackageManager().getPackageInfo("com.bjw.ComAssistant", PackageManager.GET_CONFIGURATIONS);
            String versionName = pinfo.versionName;
//			String versionCode = String.valueOf(pinfo.versionCode);
            setTitle(appName + " V" + versionName);
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }
        // 获取页面组件对象
        editTextRecDisp = (EditText) findViewById(R.id.editTextRecDisp);// 接收显示区
        editTextLines = (EditText) findViewById(R.id.editTextLines);// 接收显示区行数
        // 发送报文输入框
        editTextCOMA = (EditText) findViewById(R.id.editTextCOMA);
        editTextCOMB = (EditText) findViewById(R.id.editTextCOMB);
        editTextCOMC = (EditText) findViewById(R.id.editTextCOMC);
        editTextCOMD = (EditText) findViewById(R.id.editTextCOMD);
        // 自动发送时间输入框
        editTextTimeCOMA = (EditText) findViewById(R.id.editTextTimeCOMA);
        editTextTimeCOMB = (EditText) findViewById(R.id.editTextTimeCOMB);
        editTextTimeCOMC = (EditText) findViewById(R.id.editTextTimeCOMC);
        editTextTimeCOMD = (EditText) findViewById(R.id.editTextTimeCOMD);
        // 自动清理复选框
        checkBoxAutoClear = (CheckBox) findViewById(R.id.checkBoxAutoClear);
        // 自动发送复选框
        checkBoxAutoCOMA = (CheckBox) findViewById(R.id.checkBoxAutoCOMA);
        checkBoxAutoCOMB = (CheckBox) findViewById(R.id.checkBoxAutoCOMB);
        checkBoxAutoCOMC = (CheckBox) findViewById(R.id.checkBoxAutoCOMC);
        checkBoxAutoCOMD = (CheckBox) findViewById(R.id.checkBoxAutoCOMD);
        // 清除按钮
        ButtonClear = (Button) findViewById(R.id.ButtonClear);
        // 发送按钮
        ButtonSendCOMA = (Button) findViewById(R.id.ButtonSendCOMA);
        ButtonSendCOMB = (Button) findViewById(R.id.ButtonSendCOMB);
        ButtonSendCOMC = (Button) findViewById(R.id.ButtonSendCOMC);
        ButtonSendCOMD = (Button) findViewById(R.id.ButtonSendCOMD);
        // 串口开关按钮
        toggleButtonCOMA = (ToggleButton) findViewById(R.id.toggleButtonCOMA);
        toggleButtonCOMB = (ToggleButton) findViewById(R.id.ToggleButtonCOMB);
        toggleButtonCOMC = (ToggleButton) findViewById(R.id.ToggleButtonCOMC);
        toggleButtonCOMD = (ToggleButton) findViewById(R.id.ToggleButtonCOMD);
        // 串口选择下拉框
        SpinnerCOMA = (Spinner) findViewById(R.id.SpinnerCOMA);
        SpinnerCOMB = (Spinner) findViewById(R.id.SpinnerCOMB);
        SpinnerCOMC = (Spinner) findViewById(R.id.SpinnerCOMC);
        SpinnerCOMD = (Spinner) findViewById(R.id.SpinnerCOMD);
        // 波特率选择下拉框
        SpinnerBaudRateCOMA = (Spinner) findViewById(R.id.SpinnerBaudRateCOMA);
        SpinnerBaudRateCOMB = (Spinner) findViewById(R.id.SpinnerBaudRateCOMB);
        SpinnerBaudRateCOMC = (Spinner) findViewById(R.id.SpinnerBaudRateCOMC);
        SpinnerBaudRateCOMD = (Spinner) findViewById(R.id.SpinnerBaudRateCOMD);
        // 发送报文格式单选按钮
        radioButtonTxt = (RadioButton) findViewById(R.id.radioButtonTxt);// 发送报文格式-txt单选按钮
        radioButtonHex = (RadioButton) findViewById(R.id.radioButtonHex);// 发送报文格式-hex单选按钮

        // 发送报文输入框 和 自动发送时间输入框 绑定软键盘输入完成点回车键监听器
        editTextCOMA.setOnEditorActionListener(new EditorActionEvent());
        editTextCOMB.setOnEditorActionListener(new EditorActionEvent());
        editTextCOMC.setOnEditorActionListener(new EditorActionEvent());
        editTextCOMD.setOnEditorActionListener(new EditorActionEvent());
        editTextTimeCOMA.setOnEditorActionListener(new EditorActionEvent());
        editTextTimeCOMB.setOnEditorActionListener(new EditorActionEvent());
        editTextTimeCOMC.setOnEditorActionListener(new EditorActionEvent());
        editTextTimeCOMD.setOnEditorActionListener(new EditorActionEvent());
        // 发送报文输入框 和 自动发送时间输入框 绑定焦点改变监听器
        editTextCOMA.setOnFocusChangeListener(new FocusChangeEvent());
        editTextCOMB.setOnFocusChangeListener(new FocusChangeEvent());
        editTextCOMC.setOnFocusChangeListener(new FocusChangeEvent());
        editTextCOMD.setOnFocusChangeListener(new FocusChangeEvent());
        editTextTimeCOMA.setOnFocusChangeListener(new FocusChangeEvent());
        editTextTimeCOMB.setOnFocusChangeListener(new FocusChangeEvent());
        editTextTimeCOMC.setOnFocusChangeListener(new FocusChangeEvent());
        editTextTimeCOMD.setOnFocusChangeListener(new FocusChangeEvent());
        // 发送报文格式单选按钮 绑定点击监听器
        radioButtonTxt.setOnClickListener(new radioButtonClickEvent());
        radioButtonHex.setOnClickListener(new radioButtonClickEvent());
        // 清除按钮 绑定点击监听器
        ButtonClear.setOnClickListener(new ButtonClickEvent());
        // 发送按钮 绑定点击监听器
        ButtonSendCOMA.setOnClickListener(new ButtonClickEvent());
        ButtonSendCOMB.setOnClickListener(new ButtonClickEvent());
        ButtonSendCOMC.setOnClickListener(new ButtonClickEvent());
        ButtonSendCOMD.setOnClickListener(new ButtonClickEvent());
        // 串口开关按钮 绑定选中状态改变监听器
        toggleButtonCOMA.setOnCheckedChangeListener(new ToggleButtonCheckedChangeEvent());
        toggleButtonCOMB.setOnCheckedChangeListener(new ToggleButtonCheckedChangeEvent());
        toggleButtonCOMC.setOnCheckedChangeListener(new ToggleButtonCheckedChangeEvent());
        toggleButtonCOMD.setOnCheckedChangeListener(new ToggleButtonCheckedChangeEvent());
        // 自动发送复选框 绑定选中状态改变监听器
        checkBoxAutoCOMA.setOnCheckedChangeListener(new CheckBoxChangeEvent());
        checkBoxAutoCOMB.setOnCheckedChangeListener(new CheckBoxChangeEvent());
        checkBoxAutoCOMC.setOnCheckedChangeListener(new CheckBoxChangeEvent());
        checkBoxAutoCOMD.setOnCheckedChangeListener(new CheckBoxChangeEvent());

        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.baudrates_value, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        // 波特率选择下拉框 绑定数据资源
        SpinnerBaudRateCOMA.setAdapter(adapter);
        SpinnerBaudRateCOMB.setAdapter(adapter);
        SpinnerBaudRateCOMC.setAdapter(adapter);
        SpinnerBaudRateCOMD.setAdapter(adapter);
        SpinnerBaudRateCOMA.setSelection(12);// 设置直接跳转到第12项（从0开始）
        SpinnerBaudRateCOMB.setSelection(12);
        SpinnerBaudRateCOMC.setSelection(12);
        SpinnerBaudRateCOMD.setSelection(12);

        // 读取设备串口资源
        mSerialPortFinder = new SerialPortFinder();
        String[] entryValues = mSerialPortFinder.getAllDevicesPath();
        List<String> allDevices = new ArrayList<>();
        for (int i = 0; i < entryValues.length; i++) {
            allDevices.add(entryValues[i]);
        }
        // 串口号下拉框 绑定数据资源
        ArrayAdapter<String> aspnDevices = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, allDevices);
        aspnDevices.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        SpinnerCOMA.setAdapter(aspnDevices);
        SpinnerCOMB.setAdapter(aspnDevices);
        SpinnerCOMC.setAdapter(aspnDevices);
        SpinnerCOMD.setAdapter(aspnDevices);
        // 设置默认值
        if (allDevices.size() > 0) {
            SpinnerCOMA.setSelection(0);
        }
        if (allDevices.size() > 1) {
            SpinnerCOMB.setSelection(1);
        }
        if (allDevices.size() > 2) {
            SpinnerCOMC.setSelection(2);
        }
        if (allDevices.size() > 3) {
            SpinnerCOMD.setSelection(3);
        }
        // 设置 串口选择下拉框 和 波特率选择下拉框 选择监听器
        SpinnerCOMA.setOnItemSelectedListener(new ItemSelectedEvent());
        SpinnerCOMB.setOnItemSelectedListener(new ItemSelectedEvent());
        SpinnerCOMC.setOnItemSelectedListener(new ItemSelectedEvent());
        SpinnerCOMD.setOnItemSelectedListener(new ItemSelectedEvent());
        SpinnerBaudRateCOMA.setOnItemSelectedListener(new ItemSelectedEvent());
        SpinnerBaudRateCOMB.setOnItemSelectedListener(new ItemSelectedEvent());
        SpinnerBaudRateCOMC.setOnItemSelectedListener(new ItemSelectedEvent());
        SpinnerBaudRateCOMD.setOnItemSelectedListener(new ItemSelectedEvent());
        DispAssistData(AssistData);
    }

    /**
     * 串口选择下拉框 和 波特率选择下拉框 选择监听器
     */
    class ItemSelectedEvent implements Spinner.OnItemSelectedListener {
        // 当用户从下拉列表中选择一个项目时，会触发onItemSelected()方法
        public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
            // 当串口或波特率下拉框选项改变时关闭串口并重置 自动发送复选框 和 串口开关按钮
            if ((arg0 == SpinnerCOMA) || (arg0 == SpinnerBaudRateCOMA)) {
                CloseComPort(ComA);
                checkBoxAutoCOMA.setChecked(false);
                toggleButtonCOMA.setChecked(false);
            } else if ((arg0 == SpinnerCOMB) || (arg0 == SpinnerBaudRateCOMB)) {
                CloseComPort(ComB);
                checkBoxAutoCOMB.setChecked(false);
                toggleButtonCOMB.setChecked(false);
            } else if ((arg0 == SpinnerCOMC) || (arg0 == SpinnerBaudRateCOMC)) {
                CloseComPort(ComC);
                checkBoxAutoCOMC.setChecked(false);
                toggleButtonCOMC.setChecked(false);
            } else if ((arg0 == SpinnerCOMD) || (arg0 == SpinnerBaudRateCOMD)) {
                CloseComPort(ComD);
                checkBoxAutoCOMD.setChecked(false);
                toggleButtonCOMD.setChecked(false);
            }
        }

        // 当用户没有选择任何项目时，会触发onNothingSelected()方法
        public void onNothingSelected(AdapterView<?> arg0) {
        }

    }

    /**
     * 发送报文输入框 和 自动发送时间输入框 焦点改变监听器(和 软键盘输入完成点回车键监听器 操作内容一致)
     */
    class FocusChangeEvent implements EditText.OnFocusChangeListener {
        public void onFocusChange(View v, boolean hasFocus) {
            if (v == editTextCOMA) {
                setSendData(editTextCOMA);
            } else if (v == editTextCOMB) {
                setSendData(editTextCOMB);
            } else if (v == editTextCOMC) {
                setSendData(editTextCOMC);
            } else if (v == editTextCOMD) {
                setSendData(editTextCOMD);
            } else if (v == editTextTimeCOMA) {
                setDelayTime(editTextTimeCOMA);
            } else if (v == editTextTimeCOMB) {
                setDelayTime(editTextTimeCOMB);
            } else if (v == editTextTimeCOMC) {
                setDelayTime(editTextTimeCOMC);
            } else if (v == editTextTimeCOMD) {
                setDelayTime(editTextTimeCOMD);
            }
        }
    }

    /**
     * 发送报文输入框 和 自动发送时间输入框 软键盘输入完成点回车键监听器(和 焦点改变监听器 操作内容一致)
     */
    class EditorActionEvent implements EditText.OnEditorActionListener {
        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
            if (v == editTextCOMA) {
                setSendData(editTextCOMA);
            } else if (v == editTextCOMB) {
                setSendData(editTextCOMB);
            } else if (v == editTextCOMC) {
                setSendData(editTextCOMC);
            } else if (v == editTextCOMD) {
                setSendData(editTextCOMD);
            } else if (v == editTextTimeCOMA) {
                setDelayTime(editTextTimeCOMA);
            } else if (v == editTextTimeCOMB) {
                setDelayTime(editTextTimeCOMB);
            } else if (v == editTextTimeCOMC) {
                setDelayTime(editTextTimeCOMC);
            } else if (v == editTextTimeCOMD) {
                setDelayTime(editTextTimeCOMD);
            }
            return false;
        }
    }

    /**
     * 发送报文格式单选按钮 点击监听器
     */
    class radioButtonClickEvent implements RadioButton.OnClickListener {
        public void onClick(View v) {
            if (v == radioButtonTxt) {
                // 发送报文输入框 设置文本输入监听器
                // 创建一个 TextKeyListener 实例，设置文本输入时不自动大写，并且不自动纠正拼写错误
                KeyListener TxtkeyListener = new TextKeyListener(Capitalize.NONE, false);
                editTextCOMA.setKeyListener(TxtkeyListener);//
                editTextCOMB.setKeyListener(TxtkeyListener);
                editTextCOMC.setKeyListener(TxtkeyListener);
                editTextCOMD.setKeyListener(TxtkeyListener);
                AssistData.setTxtMode(true);// 设置发送报文格式模式为TXT
            } else if (v == radioButtonHex) {
                // 发送报文输入框 设置文本输入监听器
                // 创建一个自定义的 NumberKeyListener 实例，用于限制输入为十六进制字符
                KeyListener HexkeyListener = new NumberKeyListener() {
                    public int getInputType() {
                        // 设置输入类型为文本
                        return InputType.TYPE_CLASS_TEXT;
                    }

                    @Override
                    protected char[] getAcceptedChars() {
                        // 返回允许输入的字符数组，这里只允许输入十六进制字符
                        return new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F'};
                    }
                };
                editTextCOMA.setKeyListener(HexkeyListener);
                editTextCOMB.setKeyListener(HexkeyListener);
                editTextCOMC.setKeyListener(HexkeyListener);
                editTextCOMD.setKeyListener(HexkeyListener);
                AssistData.setTxtMode(false);// 设置发送报文格式模式为HEX
            }
            // 重新设置发送报文（发送报文格式模式变化时用于格式化）
            editTextCOMA.setText(AssistData.getSendA());
            editTextCOMB.setText(AssistData.getSendB());
            editTextCOMC.setText(AssistData.getSendC());
            editTextCOMD.setText(AssistData.getSendD());
            // 重新设置发送报文（主要设置SerialHelper的循环发送报文）
            setSendData(editTextCOMA);
            setSendData(editTextCOMB);
            setSendData(editTextCOMC);
            setSendData(editTextCOMD);
        }
    }

    /**
     * 自动发送复选框 选中状态改变监听器
     */
    class CheckBoxChangeEvent implements CheckBox.OnCheckedChangeListener {
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            // 只有在串口开启状态时才能选中，否则自动取消选择
            if (buttonView == checkBoxAutoCOMA) {
                if (!toggleButtonCOMA.isChecked() && isChecked) {
                    buttonView.setChecked(false);
                    return;
                }
                SetLoopData(ComA, editTextCOMA.getText().toString());// 设置循环发送报文
                SetAutoSend(ComA, isChecked);// 设置串口自动发送
            } else if (buttonView == checkBoxAutoCOMB) {
                if (!toggleButtonCOMB.isChecked() && isChecked) {
                    buttonView.setChecked(false);
                    return;
                }
                SetLoopData(ComB, editTextCOMB.getText().toString());
                SetAutoSend(ComB, isChecked);
            } else if (buttonView == checkBoxAutoCOMC) {
                if (!toggleButtonCOMC.isChecked() && isChecked) {
                    buttonView.setChecked(false);
                    return;
                }
                SetLoopData(ComC, editTextCOMC.getText().toString());
                SetAutoSend(ComC, isChecked);
            } else if (buttonView == checkBoxAutoCOMD) {
                if (!toggleButtonCOMD.isChecked() && isChecked) {
                    buttonView.setChecked(false);
                    return;
                }
                SetLoopData(ComD, editTextCOMD.getText().toString());
                SetAutoSend(ComD, isChecked);
            }
        }
    }

    /**
     * 清除按钮 和 发送按钮 点击监听器
     */
    class ButtonClickEvent implements View.OnClickListener {
        public void onClick(View v) {
            if (v == ButtonClear) {
                editTextRecDisp.setText("");// 清除接收显示区
            } else if (v == ButtonSendCOMA) {
                sendPortData(ComA, editTextCOMA.getText().toString());// 发送数据到串口
            } else if (v == ButtonSendCOMB) {
                sendPortData(ComB, editTextCOMB.getText().toString());
            } else if (v == ButtonSendCOMC) {
                sendPortData(ComC, editTextCOMC.getText().toString());
            } else if (v == ButtonSendCOMD) {
                sendPortData(ComD, editTextCOMD.getText().toString());
            }
        }
    }

    /**
     * 串口开关按钮 选中状态改变监听器
     */
    class ToggleButtonCheckedChangeEvent implements ToggleButton.OnCheckedChangeListener {
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (buttonView == toggleButtonCOMA) {
                if (isChecked) {
                    // 当其他串口也开启，且开启串口与当前准备开启串口一致时，不允许开启，且提示冲突
                    if (toggleButtonCOMB.isChecked() && SpinnerCOMA.getSelectedItemPosition() == SpinnerCOMB.getSelectedItemPosition()) {
                        ShowMessage("串口 " + SpinnerCOMA.getSelectedItem().toString() + " 已开启");
                        buttonView.setChecked(false);
                    } else if (toggleButtonCOMC.isChecked() && SpinnerCOMA.getSelectedItemPosition() == SpinnerCOMC.getSelectedItemPosition()) {
                        ShowMessage("串口 " + SpinnerCOMA.getSelectedItem().toString() + " 已开启");
                        buttonView.setChecked(false);
                    } else if (toggleButtonCOMD.isChecked() && SpinnerCOMA.getSelectedItemPosition() == SpinnerCOMD.getSelectedItemPosition()) {
                        ShowMessage("串口 " + SpinnerCOMA.getSelectedItem().toString() + " 已开启");
                        buttonView.setChecked(false);
                    } else {
//						ComA=new SerialControl("/dev/s3c2410_serial0", "9600");
                        // 开启串口
                        ComA.setPort(SpinnerCOMA.getSelectedItem().toString());
                        ComA.setBaudRate(SpinnerBaudRateCOMA.getSelectedItem().toString());
                        OpenComPort(ComA);
                    }
                } else {
                    // 关闭串口，并复位自动发送复选框
                    CloseComPort(ComA);
                    checkBoxAutoCOMA.setChecked(false);
                }
            } else if (buttonView == toggleButtonCOMB) {
                if (isChecked) {
                    if (toggleButtonCOMA.isChecked() && SpinnerCOMB.getSelectedItemPosition() == SpinnerCOMA.getSelectedItemPosition()) {
                        ShowMessage("串口 " + SpinnerCOMB.getSelectedItem().toString() + " 已开启");
                        buttonView.setChecked(false);
                    } else if (toggleButtonCOMC.isChecked() && SpinnerCOMB.getSelectedItemPosition() == SpinnerCOMC.getSelectedItemPosition()) {
                        ShowMessage("串口 " + SpinnerCOMB.getSelectedItem().toString() + " 已开启");
                        buttonView.setChecked(false);
                    } else if (toggleButtonCOMD.isChecked() && SpinnerCOMB.getSelectedItemPosition() == SpinnerCOMD.getSelectedItemPosition()) {
                        ShowMessage("串口 " + SpinnerCOMB.getSelectedItem().toString() + " 已开启");
                        buttonView.setChecked(false);
                    } else {
//						ComB=new SerialControl("/dev/s3c2410_serial1", "9600");
                        ComB.setPort(SpinnerCOMB.getSelectedItem().toString());
                        ComB.setBaudRate(SpinnerBaudRateCOMB.getSelectedItem().toString());
                        OpenComPort(ComB);
                    }
                } else {
                    CloseComPort(ComB);
                    checkBoxAutoCOMB.setChecked(false);
                }
            } else if (buttonView == toggleButtonCOMC) {
                if (isChecked) {
                    if (toggleButtonCOMA.isChecked() && SpinnerCOMC.getSelectedItemPosition() == SpinnerCOMA.getSelectedItemPosition()) {
                        ShowMessage("串口 " + SpinnerCOMC.getSelectedItem().toString() + " 已开启");
                        buttonView.setChecked(false);
                    } else if (toggleButtonCOMB.isChecked() && SpinnerCOMC.getSelectedItemPosition() == SpinnerCOMB.getSelectedItemPosition()) {
                        ShowMessage("串口 " + SpinnerCOMC.getSelectedItem().toString() + " 已开启");
                        buttonView.setChecked(false);
                    } else if (toggleButtonCOMD.isChecked() && SpinnerCOMC.getSelectedItemPosition() == SpinnerCOMD.getSelectedItemPosition()) {
                        ShowMessage("串口 " + SpinnerCOMC.getSelectedItem().toString() + " 已开启");
                        buttonView.setChecked(false);
                    } else {
                        //					ComC=new SerialControl("/dev/s3c2410_serial2", "9600");
                        ComC.setPort(SpinnerCOMC.getSelectedItem().toString());
                        ComC.setBaudRate(SpinnerBaudRateCOMC.getSelectedItem().toString());
                        OpenComPort(ComC);
                    }
                } else {
                    CloseComPort(ComC);
                    checkBoxAutoCOMC.setChecked(false);
                }
            } else if (buttonView == toggleButtonCOMD) {
                if (isChecked) {
                    if (toggleButtonCOMA.isChecked() && SpinnerCOMD.getSelectedItemPosition() == SpinnerCOMA.getSelectedItemPosition()) {
                        ShowMessage("串口 " + SpinnerCOMD.getSelectedItem().toString() + " 已开启");
                        buttonView.setChecked(false);
                    } else if (toggleButtonCOMB.isChecked() && SpinnerCOMD.getSelectedItemPosition() == SpinnerCOMB.getSelectedItemPosition()) {
                        ShowMessage("串口 " + SpinnerCOMD.getSelectedItem().toString() + " 已开启");
                        buttonView.setChecked(false);
                    } else if (toggleButtonCOMC.isChecked() && SpinnerCOMD.getSelectedItemPosition() == SpinnerCOMC.getSelectedItemPosition()) {
                        ShowMessage("串口 " + SpinnerCOMD.getSelectedItem().toString() + " 已开启");
                        buttonView.setChecked(false);
                    } else {
                        //					ComD=new SerialControl("/dev/s3c2410_serial3", "9600");
                        ComD.setPort(SpinnerCOMD.getSelectedItem().toString());
                        ComD.setBaudRate(SpinnerBaudRateCOMD.getSelectedItem().toString());
                        OpenComPort(ComD);
                    }
                } else {
                    CloseComPort(ComD);
                    checkBoxAutoCOMD.setChecked(false);
                }
            }
        }
    }

    /**
     * 继承SerialHelper对象，重构onDataReceived方法
     */
    private class SerialControl extends SerialHelper {

        @Override
        protected void onDataReceived(final ComBean ComRecData) {
            DispQueue.AddQueue(ComRecData);
			/*
			runOnUiThread(new Runnable()
			{
				public void run()
				{
					DispRecData(ComRecData);
				}
			});*/
        }

        @Override
        protected void showErrMsg(String msg) {
            runOnUiThread(() -> ShowMessage(msg));
        }
    }

    /**
     * 处理接收报文线程
     */
    private class DispQueueThread extends Thread {
        private Queue<ComBean> QueueList = new LinkedList<>();

        @Override
        public void run() {
            super.run();
            while (!isInterrupted()) {// 线程未中断
                final ComBean ComData;
                while ((ComData = QueueList.poll()) != null) {
                    // 将UI操作更细粒度化，避免阻塞 @date 2024-11-01
//                    runOnUiThread(() -> DispRecData(ComData));
                    DispRecData(ComData);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    break;
                }
            }
        }

        public synchronized void AddQueue(ComBean ComData) {
            QueueList.add(ComData);
        }
    }

    /**
     * 使用AssistData数据初始化发送报文输入框、报文格式单选框、自动发送时间输入框控件
     *
     * @param AssistData
     */
    private void DispAssistData(AssistBean AssistData) {
        // 初始化发送报文输入框内容
        editTextCOMA.setText(AssistData.getSendA());
        editTextCOMB.setText(AssistData.getSendB());
        editTextCOMC.setText(AssistData.getSendC());
        editTextCOMD.setText(AssistData.getSendD());
        setSendData(editTextCOMA);
        setSendData(editTextCOMB);
        setSendData(editTextCOMC);
        setSendData(editTextCOMD);
        // 初始化发送报文格式单选框
        if (AssistData.isTxt()) {
            radioButtonTxt.setChecked(true);
        } else {
            radioButtonHex.setChecked(true);
        }
        // 初始化自动发送时间输入框
        editTextTimeCOMA.setText(AssistData.sTimeA);
        editTextTimeCOMB.setText(AssistData.sTimeB);
        editTextTimeCOMC.setText(AssistData.sTimeC);
        editTextTimeCOMD.setText(AssistData.sTimeD);
        setDelayTime(editTextTimeCOMA);
        setDelayTime(editTextTimeCOMB);
        setDelayTime(editTextTimeCOMC);
        setDelayTime(editTextTimeCOMD);
    }

    /**
     * 保存发送报文、发送格式、自动发送时间等数据
     *
     * @param AssistData
     */
    private void saveAssistData(AssistBean AssistData) {
        AssistData.sTimeA = editTextTimeCOMA.getText().toString();
        AssistData.sTimeB = editTextTimeCOMB.getText().toString();
        AssistData.sTimeC = editTextTimeCOMC.getText().toString();
        AssistData.sTimeD = editTextTimeCOMD.getText().toString();
        // 获取名为 "ComAssistant" 的 SharedPreferences 对象(用于存储和读取应用的偏好设置)，模式为私有
        SharedPreferences msharedPreferences = getSharedPreferences("ComAssistant", Context.MODE_PRIVATE);
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(AssistData);
            String sBase64 = new String(Base64.encode(baos.toByteArray(), 0));// 将AssistBean对象写为Base64字符串
            // 保存数据
            SharedPreferences.Editor editor = msharedPreferences.edit();
            editor.putString("AssistData", sBase64);
//            editor.commit();
            editor.apply(); // 或者使用 commit()，但 apply() 更高效
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 读取保存的AssistBean对象
     *
     * @return
     */
    private AssistBean getAssistData() {
        SharedPreferences msharedPreferences = getSharedPreferences("ComAssistant", Context.MODE_PRIVATE);
        AssistBean AssistData = new AssistBean();
        try {
            String personBase64 = msharedPreferences.getString("AssistData", "");// 读取AssistBean对象base64字符串
            byte[] base64Bytes = Base64.decode(personBase64.getBytes(), 0);
            ByteArrayInputStream bais = new ByteArrayInputStream(base64Bytes);
            ObjectInputStream ois = new ObjectInputStream(bais);
            AssistData = (AssistBean) ois.readObject();
            return AssistData;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return AssistData;
    }

    /**
     * 设置自动发送时间
     *
     * @param v
     */
    private void setDelayTime(TextView v) {
        if (v == editTextTimeCOMA) {
            AssistData.sTimeA = v.getText().toString();
            SetiDelayTime(ComA, v.getText().toString());// 设置SerialHelper的自动发送时间
        } else if (v == editTextTimeCOMB) {
            AssistData.sTimeB = v.getText().toString();
            SetiDelayTime(ComB, v.getText().toString());
        } else if (v == editTextTimeCOMC) {
            AssistData.sTimeC = v.getText().toString();
            SetiDelayTime(ComC, v.getText().toString());
        } else if (v == editTextTimeCOMD) {
            AssistData.sTimeD = v.getText().toString();
            SetiDelayTime(ComD, v.getText().toString());
        }
    }

    /**
     * 设置发送报文
     *
     * @param v
     */
    private void setSendData(TextView v) {
        if (v == editTextCOMA) {
            AssistData.setSendA(v.getText().toString());
            SetLoopData(ComA, v.getText().toString());// 设置SerialHelper的循环发送报文
        } else if (v == editTextCOMB) {
            AssistData.setSendB(v.getText().toString());
            SetLoopData(ComB, v.getText().toString());
        } else if (v == editTextCOMC) {
            AssistData.setSendC(v.getText().toString());
            SetLoopData(ComC, v.getText().toString());
        } else if (v == editTextCOMD) {
            AssistData.setSendD(v.getText().toString());
            SetLoopData(ComD, v.getText().toString());
        }
    }

    /**
     * 设置SerialHelper的自动发送时间
     *
     * @param ComPort
     * @param sTime
     */
    private void SetiDelayTime(SerialHelper ComPort, String sTime) {
        ComPort.setiDelay(Integer.parseInt(sTime));
    }

    /**
     * 设置SerialHelper的循环发送报文
     *
     * @param ComPort
     * @param sLoopData
     */
    private void SetLoopData(SerialHelper ComPort, String sLoopData) {
        if (radioButtonTxt.isChecked()) {
            ComPort.setTxtLoopData(sLoopData);
        } else if (radioButtonHex.isChecked()) {
            ComPort.setHexLoopData(sLoopData);
        }
    }

    /**
     * 处理接收报文，并更新显示
     *
     * @param ComRecData
     */
    private void DispRecData(ComBean ComRecData) {
        // 拼接报文显示格式
        StringBuilder sMsg = new StringBuilder();
        sMsg.append(ComRecData.sRecTime).append("[").append(ComRecData.sComPort).append("]");
        if (AssistData.isTxt()) {// 根据发送报文格式类型格式化数据
            sMsg.append("[Txt] ").append(new String(ComRecData.bRec));
        } else {
            sMsg.append("[Hex] ").append(HexUtil.bytesToHexWithSpaces(ComRecData.bRec));
        }
        sMsg.append("\r\n");
        // 在UI线程中更新UI（将UI操作更细粒度化，避免阻塞 @date 2024-11-01）
        runOnUiThread(() -> {
            if ((iRecLines > 500) && (checkBoxAutoClear.isChecked())) {// 如果勾选自动清理，当行数超过500，则自动清理
                editTextRecDisp.setText(sMsg);
                iRecLines = 0;
            } else {
                editTextRecDisp.append(sMsg);// 将接收信息显示到文本框中
                iRecLines++;// 统计接收行数
            }
            editTextLines.setText(String.valueOf(iRecLines)); // 显示接收行数
        });
    }

    /**
     * 设置串口自动发送
     *
     * @param ComPort
     * @param isAutoSend
     */
    private void SetAutoSend(SerialHelper ComPort, boolean isAutoSend) {
        if (isAutoSend) {
            ComPort.startAutoSend();
        } else {
            ComPort.stopAutoSend();
        }
    }

    /**
     * 发送数据到串口
     *
     * @param ComPort
     * @param sOut
     */
    private void sendPortData(SerialHelper ComPort, String sOut) {
        if (ComPort != null && ComPort.isOpen()) {
            if (radioButtonTxt.isChecked()) {
                ComPort.sendTxt(sOut);
            } else if (radioButtonHex.isChecked()) {
                ComPort.sendHex(sOut);
            }
        }
    }

    /**
     * 开启串口
     *
     * @param ComPort
     */
    private void OpenComPort(SerialHelper ComPort) {
        try {
            ComPort.open();
        } catch (SecurityException e) {
            ShowMessage("违反安全策略闲置!");
        } catch (IOException e) {
            ShowMessage("输入/输出操作异常!");
        } catch (InvalidParameterException e) {
            ShowMessage("参数异常!");
        }
    }

    /**
     * 关闭串口
     *
     * @param ComPort
     */
    private void CloseComPort(SerialHelper ComPort) {
        if (ComPort != null) {
//            ComPort.stopSend();// 关闭自动发送
            ComPort.close();
        }
    }

    private void ShowMessage(String sMsg) {
        Toast.makeText(this, sMsg, Toast.LENGTH_SHORT).show();
    }
}